package com.yingxin.yx.framework.mybatisplus.generator;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.FileType;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @author fanchao
 */
public class FreemarkerTemplateEnginePlus extends FreemarkerTemplateEngine {

    private CodeConfig codeConfig;

    @Override
    public AbstractTemplateEngine mkdirs() {

        Map<String, String> packageInfo = this.getConfigBuilder().getPackageInfo();
        String moduleName = packageInfo.get("ModuleName");
        boolean flag = false;
        if (StringUtils.isNotEmpty(codeConfig.getPackage2())) {
            flag = true;
            moduleName = moduleName + "\\" + codeConfig.getPackage2();
        }

        if (StringUtils.isNotEmpty(codeConfig.getPackage3())) {
            flag = true;
            moduleName = moduleName + "\\" + codeConfig.getPackage3();
        }


        // 输出文件路径
        Map<String, String> pathInfo = this.getConfigBuilder().getPathInfo();
        // 添加 vo 输出文件路径
        String voPath = pathInfo.get("entity_path").replace("entity", "vo");
        pathInfo.put("vo_path", voPath);
        // 添加 req 输出文件路径
        String reqPath = voPath + File.separator + "req";
        pathInfo.put("req_path", reqPath);
        // 添加 resp 输出文件路径
        String respPath = voPath + File.separator + "resp";
        pathInfo.put("resp_path", respPath);
        // 添加 builder 输出文件路径
        String builderPath = pathInfo.get("entity_path") + File.separator + "builder";
        pathInfo.put("builder_path", builderPath);

        if (flag) {
            for (String key : pathInfo.keySet()) {
                String value = pathInfo.get(key);
                pathInfo.put(key, value.replace(packageInfo.get("ModuleName"), moduleName));
            }
        }

        pathInfo.forEach((key, value) -> {
            File dir = new File(value);
            if (!dir.exists()) {
                boolean result = dir.mkdirs();
                if (result) {
                    logger.debug("创建目录： [" + value + "]");
                }
            }

        });
        return this;
    }

    @Override
    public AbstractTemplateEngine batchOutput() {
        try {

            // codeConfig
            if (codeConfig == null) {
                codeConfig = new CodeConfig();
            }

            List<TableInfo> tableInfoList = this.getConfigBuilder().getTableInfoList();
            Iterator var2 = tableInfoList.iterator();

            while (var2.hasNext()) {
                TableInfo tableInfo = (TableInfo) var2.next();
                Map<String, Object> objectMap = this.getObjectMap(tableInfo);
                Map<String, String> pathInfo = this.getConfigBuilder().getPathInfo();
                TemplateConfig template = this.getConfigBuilder().getTemplate();
                InjectionConfig injectionConfig = this.getConfigBuilder().getInjectionConfig();

                // Vo Builder 包路径
                Map<String, String> packageInfo = (Map<String, String>) objectMap.get("package");
                packageInfo.put("MapperPackage", packageInfo.get("Entity").replace("entity", "mapper"));
                packageInfo.put("ReqVoPackage", packageInfo.get("Entity").replace("entity", "vo.req"));
                packageInfo.put("RespVoPackage", packageInfo.get("Entity").replace("entity", "vo.resp"));
                packageInfo.put("BuilderPackage", packageInfo.get("Entity") + ".builder");

                String moduleName = packageInfo.get("ModuleName");
                boolean flag = false;
                if (StringUtils.isNotEmpty(codeConfig.getPackage2())) {
                    flag = true;
                    moduleName = moduleName + "." + codeConfig.getPackage2();
                }

                if (StringUtils.isNotEmpty(codeConfig.getPackage3())) {
                    flag = true;
                    moduleName = moduleName + "." + codeConfig.getPackage3();
                }

                if (flag) {
                    for (String key : packageInfo.keySet()) {
                        if ("ModuleName".equals(key)) {
                            continue;
                        }
                        String value = packageInfo.get(key);
                        packageInfo.put(key, value.replace(packageInfo.get("ModuleName"), moduleName));
                    }
                }


                // RespVo 对象名称和父类名称
                objectMap.put("superRespVoClass", "CommonRespVo");
                objectMap.put("RespVo", tableInfo.getEntityName() + "RespVo");
                // CreateVo 对象名称和父类名称
                objectMap.put("CreateVo", tableInfo.getEntityName() + "CreateVo");
                // QueryVo 对象名称和父类名称
                objectMap.put("superQueryVoClass", "PageIn");
                objectMap.put("QueryVo", tableInfo.getEntityName() + "QueryVo");
                // UpdateVo 对象名称和父类名称
                objectMap.put("superUpdateVoClass", tableInfo.getEntityName() + "CreateVo");
                objectMap.put("UpdateVo", tableInfo.getEntityName() + "UpdateVo");
                // Builder 对象名称和父类名称
                objectMap.put("Builder", tableInfo.getEntityName() + "Builder");

                // IService 的引用变量名称
                String serviceName = tableInfo.getServiceName();
                objectMap.put("serviceVariable", CodeConfig.firstLetterLowerCase(serviceName.substring(1)));

                // String comment = tableInfo.getComment();

                // entityVariable
                objectMap.put("entityVariable", codeConfig.getEntityVariable());
                objectMap.put("buildType", codeConfig.getBuildType());

                objectMap.put("entityMapper", tableInfo.getEntityName() + "Mapper");
                objectMap.put("entityMapperVariable", CodeConfig.firstLetterLowerCase(tableInfo.getEntityName()) + "Mapper");

                if (!CodeConfig.NORMAL.equals(codeConfig.getBuildType())) {

                    // subject
                    objectMap.put("billClass", codeConfig.getBillClass());
                    objectMap.put("billClassVariable", codeConfig.getBillClassVariable());

                    objectMap.put("billMapper", codeConfig.getBillClass() + "Mapper");
                    objectMap.put("billMapperVariable", CodeConfig.firstLetterLowerCase(codeConfig.getBillClass()) + "Mapper");

                    // item
                    objectMap.put("itemClass", codeConfig.getItemClass());
                    objectMap.put("itemClassVariable", codeConfig.getItemClassVariable());

                    objectMap.put("itemMapper", codeConfig.getItemClass() + "Mapper");
                    objectMap.put("itemMapperVariable", CodeConfig.firstLetterLowerCase(codeConfig.getItemClass()) + "Mapper");

                    // objectMap.put("itemBuilderClass", codeConfig.getItemClass() + "Builder");
                    objectMap.put("itemServiceClass", "I" + codeConfig.getItemClass() + "Service");
                    objectMap.put("itemServiceClassVariable", CodeConfig.firstLetterLowerCase(codeConfig.getItemClass()) + "Service");

                    objectMap.put("foreignKey", codeConfig.getForeignKey());
                    String[] array = codeConfig.getForeignKey().split("_");
                    StringBuilder foreignProperty = new StringBuilder();
                    for (int i = 0; i < array.length; i++) {
                        if (i == 0) {
                            foreignProperty.append(array[i]);
                        } else {
                            foreignProperty.append(CodeConfig.firstLetterUpperCase(array[i]));
                        }
                    }
                    objectMap.put("foreignProperty", foreignProperty.toString());
                    objectMap.put("firstLetterUpperForeignProperty", CodeConfig.firstLetterUpperCase(foreignProperty.toString()));
                }


                // 字段类型 验证
                List<TableField> fields = tableInfo.getFields();
                Iterator var10 = fields.iterator();
                while (var10.hasNext()) {
                    TableField field = (TableField) var10.next();
                    // id
                    if (field.getPropertyName().equals("id")) {
                        field.setKeyFlag(true);
                        field.setConvert(true);
                        field.setColumnType(DbColumnType.STRING);
                    }
                    // date
                    if (field.getColumnType().equals(DbColumnType.LOCAL_DATE_TIME)) {
                        field.setColumnType(DbColumnType.DATE);
                    }
                    // char varchar
                    if (field.getType().startsWith("char")) {
                        String t = field.getType().substring(5);
                        t = t.substring(0, t.length() - 1);
                        Map<String, Object> map = field.getCustomMap();
                        if (map == null) {
                            map = new HashMap<>();
                        }
                        map.put("length", "@Length(max = " + t + ")");
                        field.setCustomMap(map);
                    } else if (field.getType().startsWith("varchar")) {
                        String t = field.getType().substring(8);
                        t = t.substring(0, t.length() - 1);
                        Map<String, Object> map = field.getCustomMap();
                        if (map == null) {
                            map = new HashMap<>();
                        }
                        map.put("length", "@Length(max = " + t + ")");
                        field.setCustomMap(map);
                    }

                    // int bigint
                    if (field.getType().startsWith("int")) {
                        if (field.getColumnName().equals("creator_id")
                                || field.getColumnName().equals("updater_id")) {
                            field.setColumnType(DbColumnType.STRING);
                        }
                    } else if (field.getType().startsWith("bigint")) {
                        field.setColumnType(DbColumnType.STRING);
                    }

                    if (field.getType().equals("datetime")) {
                        Map<String, Object> map = field.getCustomMap();
                        if (map == null) {
                            map = new HashMap<>();
                        }
                        map.put("datetime", "@JsonFormat(pattern = \"yyyy-MM-dd HH:mm\", timezone = \"GMT+8\")");
                        field.setCustomMap(map);
                    }

                    if (field.getType().equals("date")) {
                        Map<String, Object> map = field.getCustomMap();
                        if (map == null) {
                            map = new HashMap<>();
                        }
                        map.put("date", "@JsonFormat(pattern = \"yyyy-MM-dd\", timezone = \"GMT+8\")");
                        field.setCustomMap(map);
                    }

                    // sort
                    if (field.getPropertyName().equals("sort")) {
                        Map<String, Object> map = field.getCustomMap();
                        if (map == null) {
                            map = new HashMap<>();
                        }
                        map.put("range", "@Range(min = 0, max = 99999999)");
                        field.setCustomMap(map);
                    }

                    if (field.getComment() != null) {
                        Map<String, Object> map = field.getCustomMap();
                        if (map == null) {
                            map = new HashMap<>();
                        }
                        field.setCustomMap(map);
                        if (field.getComment().contains("[eq]")) {
                            map.put("qc", "eq");
                            field.setComment(field.getComment().replace("[eq]", ""));
                        }
                        if (field.getComment().contains("[like]")) {
                            map.put("qc", "like");
                            field.setComment(field.getComment().replace("[like]", ""));
                        }
                    }
                }

                if (null != injectionConfig) {
                    injectionConfig.initTableMap(tableInfo);
                    objectMap.put("cfg", injectionConfig.getMap());
                    List<FileOutConfig> focList = injectionConfig.getFileOutConfigList();
                    if (CollectionUtils.isNotEmpty(focList)) {
                        Iterator var9 = focList.iterator();

                        while (var9.hasNext()) {
                            FileOutConfig foc = (FileOutConfig) var9.next();
                            if (this.isCreate(FileType.OTHER, foc.outputFile(tableInfo))) {
                                this.writerFile(objectMap, foc.getTemplatePath(), foc.outputFile(tableInfo));
                            }
                        }
                    }
                }


                String entityName = tableInfo.getEntityName();
                String controllerFile;
                if (null != entityName && null != pathInfo.get("entity_path")) {
                    controllerFile = String.format((String) pathInfo.get("entity_path") + File.separator + "%s" + this.suffixJavaOrKt(), entityName);
                    if (this.isCreate(FileType.ENTITY, controllerFile)) {
                        // this.writerFile(objectMap, this.templateFilePath(template.getEntity(this.getConfigBuilder().getGlobalConfig().isKotlin())), controllerFile);
                        template.getEntity(this.getConfigBuilder().getGlobalConfig().isKotlin());
                        this.writerFile(objectMap, this.templateFilePath("ftl/Entity.java"), controllerFile);
                    }
                }

                if (null != tableInfo.getMapperName() && null != pathInfo.get("mapper_path")) {
                    controllerFile = String.format((String) pathInfo.get("mapper_path") + File.separator + tableInfo.getMapperName() + this.suffixJavaOrKt(), entityName);
                    if (this.isCreate(FileType.MAPPER, controllerFile)) {
                        // this.writerFile(objectMap, this.templateFilePath(template.getMapper()), controllerFile);
                        this.writerFile(objectMap, this.templateFilePath("ftl/Mapper.java"), controllerFile);
                    }
                }


                /*
                pathInfo.put("xml_path", "c:/codes/src/main/java/com/yingxin/yxerp/module/" + moduleName + "/mapper/mysql/"
                        + tableInfo.getEntityName() + "Mapper.xml");

                 */

                if (null != tableInfo.getXmlName() && null != pathInfo.get("xml_path")) {
                    controllerFile = String.format((String) pathInfo.get("xml_path") + File.separator + tableInfo.getXmlName() + ".xml", entityName);
                    if (this.isCreate(FileType.XML, controllerFile)) {
                        // this.writerFile(objectMap, this.templateFilePath(template.getXml()), controllerFile);
                        this.writerFile(objectMap, this.templateFilePath("ftl/Mapper.xml"), controllerFile);
                    }
                }

                if (null != tableInfo.getServiceName() && null != pathInfo.get("service_path")) {
                    controllerFile = String.format((String) pathInfo.get("service_path") + File.separator + tableInfo.getServiceName() + this.suffixJavaOrKt(), entityName);
                    if (this.isCreate(FileType.SERVICE, controllerFile)) {
                        // this.writerFile(objectMap, this.templateFilePath(template.getService()), controllerFile);
                        this.writerFile(objectMap, this.templateFilePath("ftl/Service.java"), controllerFile);
                    }
                }

                if (null != tableInfo.getServiceImplName() && null != pathInfo.get("service_impl_path")) {
                    controllerFile = String.format((String) pathInfo.get("service_impl_path") + File.separator + tableInfo.getServiceImplName() + this.suffixJavaOrKt(), entityName);
                    if (this.isCreate(FileType.SERVICE_IMPL, controllerFile)) {
                        // this.writerFile(objectMap, this.templateFilePath(template.getServiceImpl()), controllerFile);
                        this.writerFile(objectMap, this.templateFilePath("ftl/ServiceImpl.java"), controllerFile);
                    }
                }


                if (!CodeConfig.ITEM.equals(codeConfig.getBuildType())) {

                    if (null != tableInfo.getControllerName() && null != pathInfo.get("controller_path")) {
                        controllerFile = String.format((String) pathInfo.get("controller_path") + File.separator + tableInfo.getControllerName() + this.suffixJavaOrKt(), entityName);
                        if (this.isCreate(FileType.CONTROLLER, controllerFile)) {
                            //this.writerFile(objectMap, this.templateFilePath(template.getController()), controllerFile);
                            this.writerFile(objectMap, this.templateFilePath("ftl/Controller.java"), controllerFile);
                        }
                    }


                    // Builder
                    if (null != entityName && null != pathInfo.get("builder_path")) {
                        controllerFile = String.format((String) pathInfo.get("builder_path") + File.separator + "%s" + this.suffixJavaOrKt(), entityName + "Builder");
                        if (this.isCreate(FileType.OTHER, controllerFile)) {
                            this.writerFile(objectMap, this.templateFilePath("ftl/Builder.java"), controllerFile);
                        }
                    }

                }
                // vo 开启 swagger
                objectMap.put("swagger2", true);

                // RespVo

                if (null != entityName && null != pathInfo.get("resp_path")) {
                    controllerFile = String.format((String) pathInfo.get("resp_path") + File.separator + "%s" + this.suffixJavaOrKt(), entityName + "RespVo");
                    if (this.isCreate(FileType.OTHER, controllerFile)) {
                        this.writerFile(objectMap, this.templateFilePath("ftl/RespVo.java"), controllerFile);
                    }
                }

                // CreateVo QueryVo UpdateVo

                if (null != entityName && null != pathInfo.get("req_path")) {
                    controllerFile = String.format((String) pathInfo.get("req_path") + File.separator + "%s" + this.suffixJavaOrKt(), entityName + "CreateVo");
                    if (this.isCreate(FileType.OTHER, controllerFile)) {
                        // this.templateFilePath(template.getEntity(this.getConfigBuilder().getGlobalConfig().isKotlin()));
                        this.writerFile(objectMap, this.templateFilePath("ftl/CreateVo.java"), controllerFile);
                    }

                    if (!CodeConfig.ITEM.equals(codeConfig.getBuildType())) {

                        controllerFile = String.format((String) pathInfo.get("req_path") + File.separator + "%s" + this.suffixJavaOrKt(), entityName + "QueryVo");
                        if (this.isCreate(FileType.OTHER, controllerFile)) {
                            this.writerFile(objectMap, this.templateFilePath("ftl/QueryVo.java"), controllerFile);
                        }
                        controllerFile = String.format((String) pathInfo.get("req_path") + File.separator + "%s" + this.suffixJavaOrKt(), entityName + "UpdateVo");
                        if (this.isCreate(FileType.OTHER, controllerFile)) {
                            this.writerFile(objectMap, this.templateFilePath("ftl/UpdateVo.java"), controllerFile);
                        }
                    }

                }

                objectMap.put("swagger2", false);
            }
        } catch (Exception var11) {
            logger.error("无法创建文件，请检查配置信息！", var11);
        }

        return this;
    }

    public CodeConfig getCodeConfig() {
        return codeConfig;
    }

    public void setCodeConfig(CodeConfig codeConfig) {
        this.codeConfig = codeConfig;
    }
}
